package com.codeoss.framework.view.parser;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.ExpressionUtil;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.Container;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.parser.store.IComponentParserStore;
import com.codeoss.framework.view.util.DependObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public abstract class AbstractComponentParser implements IComponentParser,ApplicationContextAware {
	protected ApplicationContext applicationContext;
	@Autowired
	private IComponentParserStore componentParserStore;
	public Component parse(IParseContext parseContext, ObjectNode objectNode) {
		beforeParse(parseContext,objectNode);
		Component component=createComponent(parseContext,objectNode);
		setAttributes(parseContext,objectNode,component);
		if(isParseChildren(parseContext,objectNode,component) && component instanceof Container) {
			parseChildren(parseContext,objectNode,(Container)component);
		}
		afterParse(parseContext,objectNode,component);
		return component;
	}
	
	protected void beforeParse(IParseContext parseContext, ObjectNode objectNode) {
		
	}
	
	protected abstract Component createComponent(IParseContext parseContext, ObjectNode objectNode);
	
    protected void setAttributes(IParseContext parseContext, ObjectNode objectNode,Component component) {
		String id=objectNode.get("id").asText();
		component.setId(parseContext.getPage().getCode()+"_"+id);
		ObjectNode propertyMapNode=(ObjectNode)objectNode.get("propertyMap");
		if(propertyMapNode!=null) {
			JsonNode jsonNode=propertyMapNode.get("onClickExpression");
			if(jsonNode!=null && !"null".equals(jsonNode.asText())&&!StringUtils.isEmpty(jsonNode.asText())) {
				String onClickExpression=jsonNode.asText();
				String expressionType=Expression.EXPRESSION_TYPE_JAVASCRIPT;
				if(onClickExpression.startsWith("@")) {
					expressionType=Expression.EXPRESSION_TYPE_SPRING;
				}
				component.setOnClickExpression(ExpressionUtil.convertToExpression(onClickExpression,expressionType));
			}
			jsonNode=propertyMapNode.get("cssStyleExpression");
			if(jsonNode!=null&& !"null".equals(jsonNode.asText())&&!StringUtils.isEmpty(jsonNode.asText())) {
				String cssStyleExpression=jsonNode.asText();
				component.setCssStyleExpression(ExpressionUtil.convertLabelToExpression(cssStyleExpression,Expression.EXPRESSION_TYPE_JAVASCRIPT));
			}
			jsonNode=propertyMapNode.get("cssClassExpression");
			if(jsonNode!=null&& !"null".equals(jsonNode.asText())&&!StringUtils.isEmpty(jsonNode.asText())) {
				String cssClassExpression=jsonNode.asText();
				component.setCssClassExpression(ExpressionUtil.convertLabelToExpression(cssClassExpression,Expression.EXPRESSION_TYPE_JAVASCRIPT));
			}
			jsonNode=propertyMapNode.get("visible");
			if(jsonNode!=null&& !"null".equals(jsonNode.asText()) &&!StringUtils.isEmpty(jsonNode.asText())) {
				String visible=jsonNode.asText();
				component.setVisibleExpression(ExpressionUtil.convertToExpression(visible,Expression.EXPRESSION_TYPE_JAVASCRIPT));
			}
		}
	}
    
    protected void parseChildren(IParseContext parseContext, ObjectNode objectNode,Container container) {
    	Container oldContainer=parseContext.getParent();
    	parseContext.setParent(container);
    	ArrayNode arrayNode=(ArrayNode)objectNode.get("children");
    	for(int i=0;i<arrayNode.size();i++) {
    		ObjectNode childObjectNode=(ObjectNode)arrayNode.get(i);
    		IComponentParserStore componentParserStore=applicationContext.getBean(IComponentParserStore.class);
    		IComponentParser componentParser=componentParserStore.getComponentParser(parseContext, childObjectNode);
    		Component component=componentParser.parse(parseContext, childObjectNode);
    		component.setParent(container);
    		container.addComponent(component);
    	}
    	parseContext.setParent(oldContainer);
    }
    
    
    protected void afterParse(IParseContext parseContext, ObjectNode objectNode,Component component) {
    	
	}
    
    protected void parseExpression(IParseContext parseContext,Component component,Expression expression,String attr,boolean isDependAttr) {
		Page page=parseContext.getPage();
		DependObject dependObject=page.getDependObject();
		String script=expression.getScript();
		int index = script.indexOf("@");
		if (index != -1) {
			int from = 0;
			int to = 0;
			int len = script.length();
			StringBuilder sbLogic = new StringBuilder();
			while (index != -1) {
				sbLogic.append(script.substring(from, index));
				to = script.indexOf("@", index + 1);
				char c = script.charAt(index + 1);
				if (c == '#') {
					sbLogic.append("G_");
					sbLogic.append(script.substring(index + 2, to));
				} else {
					String name = script.substring(index + 1, to);
					sbLogic.append(name);
					if(isDependAttr) {
						Component nameComponent=page.findComponentByVarName(name);
						dependObject.add(nameComponent.getId(), component.getId(), attr);
					}	
				}
				from = to + 1;
				if (to < len - 1) {
					index = script.indexOf("@", to + 1);
				} else {
					break;
				}
			}
			if (to < len - 1) {
				sbLogic.append(script.substring(to + 1));
			}
			expression.setScript(sbLogic.toString());
		}
	}
    
    protected boolean isParseChildren(IParseContext parseContext, ObjectNode objectNode,Component component) {
    	return true;
    }
    
    public void afterPageParse(IParseContext parseContext,Component component) {
    	Expression visibleExpression=component.getVisibleExpression();
		 if(visibleExpression!=null) {
			 parseExpression(parseContext, component, visibleExpression, "visible", true);
		 }
    	if(component instanceof Container) {
    		Container c=(Container)component;
    		for(int i=0;i<c.getChildren().size();i++) {
    			Component child=c.getChildren().get(i);
    			IComponentParser componentParser=componentParserStore.getComponentParser(parseContext, child);
    			componentParser.afterPageParse(parseContext,child);
    		}
    	}
    }
    
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
    	this.applicationContext=applicationContext;
    }
}
